/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ch.repit.aglaja.client.contacts;

import ch.repit.rwt.client.Bento;
import ch.repit.rwt.client.BentoAttribute;
import ch.repit.rwt.client.BentoDef;
import ch.repit.rwt.client.BentoStatus;
import ch.repit.rwt.client.FileDescriptor;
import ch.repit.rwt.client.ObjectRef;
import ch.repit.rwt.client.logs.LogManager;
import ch.repit.rwt.client.persistence.CacheEvent;
import ch.repit.rwt.client.persistence.CacheManager;
import ch.repit.rwt.client.persistence.ObjectNotFoundException;
import ch.repit.rwt.client.persistence.ObjectStaleException;
import ch.repit.rwt.client.security.AuthorizationException;
import ch.repit.rwt.client.ui.BentoListPage;
import ch.repit.rwt.client.ui.Dialog;
import ch.repit.rwt.client.ui.Page;
import ch.repit.rwt.client.util.CountryCodes;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.StatusCodeException;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;


/**
 *
 * @author tc149752
 */
public class HouseholdsListTab extends BentoListPage {

    private String searchFilter = "";

    public HouseholdsListTab(Page topPage, BentoStatus status) {
        super(topPage, AddressDef.TYPE, status);

        if (status == BentoStatus.ACTIVE)
            setTitle("Foyers");
        else if (status == BentoStatus.TRASH)
            setTitle("Trash");
        else setTitle("erreur: " + status);
    }


    @Override
    protected void init() {

        if (super.listSupportedStatus().contains(BentoStatus.ACTIVE))
            super.addColumn("tags", "_tags", false, true);
        super.addColumn("personnes",   "_people", false);
        super.addColumn("intitulé", "_address.header", true);
        super.addColumn("localité", "_address.city", true);
        super.addColumn("email", AddressDef.ATTR_EMAIL, true);
        super.addColumn("téléphone", AddressDef.ATTR_PRIVATEPHONE, true);
        super.addNumberCommentsColumn();

        super.setSortColumn(PersonDef.ATTR_LASTNAME, true); // needed because tags is not sortable

        super.init();
    }

    
    @Override
    protected void onRowClicked(Bento data, String columnsAttributeName) {
        // this is to ignore (table-wise) clicks on the tag checkbox
        if ("_tags".equals(columnsAttributeName))
            return;
        
        if (data!=null) {
            if (data.getStatus().equals(BentoStatus.TRASH)
                    && !CacheManager.get().getCachedObject(data.getDisplayValue(PersonDef.ATTR_ADDRESSREF))
                        .getStatus().equals(BentoStatus.TRASH) ) {
                getPageNav().displayPage(new PersonTab(data.getRef(), null));
            } else {
                // normal case, check which column was clicked
                ObjectRef oref = data.getRef();
                if (columnsAttributeName.startsWith("_address."))
                    oref = new ObjectRef(data.getDisplayValue(PersonDef.ATTR_ADDRESSREF));
                getPageNav().displayPage( new ContactDetailsPage(oref) );
            }
        }
        // TBD: else create???
    }

    
    @Override
    protected ClickHandler getNewObjectHandler(final BentoDef bentoDef) {
        return new ClickHandler() {
            public void onClick(ClickEvent arg0) {
                Page newContactPage = new NewAddressPage(null);
                getPageNav().displayPage(newContactPage);
            }
        };
    }

    @Override
    protected void fillToolbarWidgets(List<Widget> leftWidgets,
                                      List<Widget> middleWidgets,
                                      List<Widget> rightWidgets) {
        super.fillToolbarWidgets(leftWidgets, middleWidgets, rightWidgets);

        final TextBox searchField = new TextBox();
        searchField.addKeyUpHandler(new KeyUpHandler()  {
            public void onKeyUp(KeyUpEvent event) {
                //LogManager.get().debug("onChange:"+searchField.getText());
                searchFilter = searchField.getText();
                resetData(CacheManager.get().getCachedObjects(PersonDef.TYPE));
            }
        } );
        leftWidgets.add(0,searchField);
    }



    @Override
    protected boolean formatObject(Bento address, Map formatedValue) {

        // intitule and city
        //Bento address = CacheManager.get().getCachedObject(bento.getDisplayValue(PersonDef.ATTR_ADDRESSREF));
        if (address != null) {
            formatedValue.put("_address.header", address.getDisplayValue(AddressDef.ATTR_HEADER));
            String city = address.getDisplayValue(AddressDef.ATTR_LOCALITY);
            if ( !CountryCodes.CH.equals(address.getDisplayValue(AddressDef.ATTR_COUNTRY)) )
                city += " ("+address.getDisplayValue(AddressDef.ATTR_COUNTRY)+")";
            formatedValue.put("_address.city", city);
        }

        // email, family if no perso
        String email = address.get(AddressDef.ATTR_EMAIL).getString();

        formatedValue.put("_email", email);

        // tags
        /* TBD
        HorizontalPanel cbp = new HorizontalPanel();
        Map<String,Bento> tagsSorted = new TreeMap();
        for (Bento tag : CacheManager.get().getCachedObjects(TagDef.TYPE)) {
            if (tag.getStatus()==BentoStatus.ACTIVE) {
                tagsSorted.put(tag.getDisplayValue(TagDef.ATTR_NAME), tag);
            }
        }
        for (Bento tag : tagsSorted.values()) {
            CheckBox cb = new CheckBox(tag.getDisplayValue(TagDef.ATTR_NAME));
            List<String> adrList = tag.get(TagDef.ATTR_ADDRESSES).getStringList();
            String adrRefStr = bento.getDisplayValue(PersonDef.ATTR_ADDRESSREF);
            cb.setValue( adrList.contains(adrRefStr) );
            cb.addClickHandler(new TagCheckBoxClickHandler(tag.getRef(), new ObjectRef(adrRefStr)));
            cbp.add(cb);
        }
         *
         */
        // how to set nowrap?
        //formatedValue.put("_tags", cbp);
        
        return super.formatObject(address, formatedValue);
    }


    @Override
    protected int sortCompare(Bento bento1, Bento bento2, String sortAttribute, boolean ascending) {
        if ("_genreIcon".equals(sortAttribute)) {
            int inverse = ascending?1:-1;
            if (bento1.get(PersonDef.ATTR_ISMALEGENDER).getBoolean() == null) return inverse;
            if (bento2.get(PersonDef.ATTR_ISMALEGENDER).getBoolean() == null) return -1*inverse;
            return (bento1.get(PersonDef.ATTR_ISMALEGENDER).getBoolean()
                    .compareTo(bento2.get(PersonDef.ATTR_ISMALEGENDER).getBoolean())) * inverse;
        }
        else if ("_address.header".equals(sortAttribute)) {
            int inverse = ascending?1:-1;
            if (bento1.getDisplayValue(PersonDef.ATTR_ADDRESSREF) == null) return inverse;
            if (bento2.getDisplayValue(PersonDef.ATTR_ADDRESSREF) == null) return -1*inverse;
            if (CacheManager.get().getCachedObject(bento1.getDisplayValue(PersonDef.ATTR_ADDRESSREF)) == null) return inverse;
            if (CacheManager.get().getCachedObject(bento2.getDisplayValue(PersonDef.ATTR_ADDRESSREF)) == null) return -1*inverse;

            BentoAttribute attr1 = CacheManager.get().getCachedObject(bento1.getDisplayValue(PersonDef.ATTR_ADDRESSREF))
                    .get(AddressDef.ATTR_HEADER);
            BentoAttribute attr2 = CacheManager.get().getCachedObject(bento2.getDisplayValue(PersonDef.ATTR_ADDRESSREF))
                    .get(AddressDef.ATTR_HEADER);

            if (attr1.getString() == null) return inverse;
            if (attr2.getString() == null) return -1*inverse;
            return (attr1.getString().compareToIgnoreCase(attr2.getString())) * inverse;
        }
        else if ("_address.city".equals(sortAttribute)) {
            int inverse = ascending?1:-1;

            if (bento1.getDisplayValue(PersonDef.ATTR_ADDRESSREF) == null) return inverse;
            if (bento2.getDisplayValue(PersonDef.ATTR_ADDRESSREF) == null) return -1*inverse;
            if (CacheManager.get().getCachedObject(bento1.getDisplayValue(PersonDef.ATTR_ADDRESSREF)) == null) return inverse;
            if (CacheManager.get().getCachedObject(bento2.getDisplayValue(PersonDef.ATTR_ADDRESSREF)) == null) return -1*inverse;

            BentoAttribute attr1 = CacheManager.get().getCachedObject(bento1.getDisplayValue(PersonDef.ATTR_ADDRESSREF))
                    .get(AddressDef.ATTR_LOCALITY);
            BentoAttribute attr2 = CacheManager.get().getCachedObject(bento2.getDisplayValue(PersonDef.ATTR_ADDRESSREF))
                    .get(AddressDef.ATTR_LOCALITY);
            
            if (attr1.getString() == null) return inverse;
            if (attr2.getString() == null) return -1*inverse;
            return (attr1.getString().compareToIgnoreCase(attr2.getString())) * inverse;
        }
        
        return super.sortCompare(bento1, bento2, sortAttribute, ascending);
    }



    @Override
    protected void resetData(List<Bento> objectList) {
        List<Bento> result = objectList;
        if (searchFilter != null && searchFilter.trim().length() > 0) {
            List<Bento> tmp = new ArrayList();
            for (Bento b : result) {
                if (matchSearch(b, PersonDef.ATTR_LASTNAME)
                        || matchSearch(b, PersonDef.ATTR_FIRSTNAME)
                        || matchSearch(CacheManager.get().getCachedObject
                        (b.getDisplayValue(PersonDef.ATTR_ADDRESSREF)), AddressDef.ATTR_HEADER) )
                    tmp.add(b);
            }
            result = tmp;
        }

        super.resetData(result);
    }


    /**
     * @param bento
     * @param attribute
     * @return returns true if the attributes matches approx the searchFilter
     * TBD: accents...
     */
    private boolean matchSearch(Bento bento, String attribute) {
        String filllower = searchFilter.trim().toLowerCase();
        if (bento!=null) {
            String av = bento.getDisplayValue(attribute);
            if (av!=null) {
                List<String> as = Arrays.asList(av.trim().toLowerCase().split(" |-"));
                for (String ass : as)
                    if (ass.startsWith(filllower))
                        return true;
            }
        }
        return false;
    }


    @Override
    public void onCacheEvent(CacheEvent event) {
        // same impl as in BentoListPage, but on both PersonDef and AddressDef
        if (event.getEventType() == CacheEvent.CacheEventType.FULL_RELOAD) {
            resetBentoList();
        } else if (event.getConcernedTypes() != null) {
            if (event.getConcernedTypes().contains(AddressDef.TYPE)
                    || event.getConcernedTypes().contains(PersonDef.TYPE)
                    || event.getConcernedTypes().contains(TagDef.TYPE))
                resetBentoList();
        }
    }

    

    private class TagCheckBoxClickHandler implements ClickHandler {

        private ObjectRef tagRef, addressRef;

        TagCheckBoxClickHandler(ObjectRef tagRef, ObjectRef addressRef) {
            this.addressRef = addressRef;
            this.tagRef = tagRef;
        }

        public void onClick(ClickEvent event) {
            Bento tag = CacheManager.get().getCachedObject(tagRef);
            if (tag != null && addressRef!= null) {
                String adrStr = addressRef.toString();
                List<String> tagRefs = tag.get(TagDef.ATTR_ADDRESSES).getStringList();
                final CheckBox cb = (CheckBox)event.getSource();
                if (cb.getValue()) {
                    if (!tagRefs.contains(adrStr))
                        tagRefs.add(adrStr);
                }
                else {
                    if (tagRefs.contains(adrStr))
                        tagRefs.remove(adrStr);
                }
                
                // now saves the tag
                LogManager.get().handling("Mise à jour du tag...");
                AsyncCallback<ObjectRef> callback = new AsyncCallback<ObjectRef>() {
                    public void onFailure(Throwable caught) {
                        if (caught instanceof StatusCodeException) {
                            LogManager.get().warningConnectionLost();
                            LogManager.get().warning("Impossible de contacter le serveur. Veuillez vérifier votre connexion Internet et recommencer");
                        } else if (caught instanceof ObjectNotFoundException) {
                            LogManager.get().warning("L'objet a été supprimé pendant que vous l'éditiez", caught);
                            CacheManager.get().refreshCache();
                        } else if (caught instanceof ObjectStaleException) {
                            LogManager.get().warning("La mise à jour a échoué, car l'objet a été modifié pendant que vous l'éditiez. Veuillez recommencer vos modifications", caught);
                            CacheManager.get().refreshCache();
                        } else if (caught instanceof AuthorizationException) {
                            LogManager.get().warning("Vous n'avez pas les droits suffisants pour effectuer cette opération", caught);
                            // could reauthenticate...
                        } else {
                            LogManager.get().error("Echec de l'enregistrement de l'objet pour une raison inconnue!", caught);
                        }
                        // in all case, revert the checkbox
                        cb.setValue(!cb.getValue());
                    }
                    public void onSuccess(ObjectRef objectRef) {
                        LogManager.get().handled("Tag mis à jour.");
                        CacheManager.get().refreshCache();
                    }
                };
                CacheManager.get().getPersistenceService().updateBento(tag, callback);
            }
        }

    }

}
